namespace Tekdev.InputValidation
{
    using System;
	using System.Data;
    using System.Collections;
    using System.Collections.Specialized;
    using System.Text.RegularExpressions;
    using System.Xml;

    internal class QueryStringUtil
    {
		#region Properties
		#endregion

		#region Constructor
        private QueryStringUtil()
        {
        }
		#endregion

		#region Custom Methods
        internal static Config Load(string configXml)
        {
			//Create and load the XmlDocument
            Config settings = new Config();
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(configXml);
            XmlElement documentElement = doc.DocumentElement;

			//Select and loop through all the pages
            XmlNodeList pages = doc.SelectNodes("configuration/pages/page");
            for (int i = 0; i < pages.Count; i++)
            {
				//Set Page attributes
                XmlNode page = pages[i];
                QueryStringPage qsPage = new QueryStringPage();
                qsPage.Url = page.Attributes["url"].Value.ToLower();
                
				//Set showError attribute (optional) (true by default)
				bool showError = true;
                XmlAttribute attrib = page.Attributes["showError"];
                if ((attrib != null) && (string.Compare(attrib.Value, "false", true) == 0))
                {
                    showError = false;
                }
                qsPage.ShowError = showError;
                
				//Create and loop through all the page parameters (page/param)
				QueryStringParamCollection qsParamColl = new QueryStringParamCollection();
                XmlNodeList paramNodeList = page.SelectNodes("param");
                for (int j = 0; j < paramNodeList.Count; j++)
                {
                    QueryStringParameter qsParamInfo = new QueryStringParameter();
                    XmlNode paramNode = paramNodeList[j];
                    
					//Retrieve and set the NAME attribute
					qsParamInfo.Name = string.Empty;
                    XmlAttribute paramAttrib = paramNode.Attributes["name"];
                    if (paramAttrib != null)
                    {
                        qsParamInfo.Name = paramAttrib.Value;
                    }

					//Retrieve and set the LENGTH attribute
                    qsParamInfo.Length = -1;
                    paramAttrib = paramNode.Attributes["length"];
                    if (paramAttrib != null)
                    {
                        qsParamInfo.Length = Convert.ToInt32(paramAttrib.Value);
                    }

					//Retrieve and set the MINLENGTH attribute
                    qsParamInfo.MinLength = -1;
                    paramAttrib = paramNode.Attributes["minLength"];
                    if (paramAttrib != null)
                    {
                        qsParamInfo.MinLength = Convert.ToInt32(paramAttrib.Value);
                    }

					//Retrieve and set the MAXLENGTH attribute
                    qsParamInfo.MaxLength = -1;
                    paramAttrib = paramNode.Attributes["maxLength"];
                    if (paramAttrib != null)
                    {
                        qsParamInfo.MaxLength = Convert.ToInt32(paramAttrib.Value);
                    }

					//Retrieve and set the TYPE attribute
                    qsParamInfo.Type = "Text";
                    paramAttrib = paramNode.Attributes["type"];
                    if (paramAttrib != null)
                    {
                        qsParamInfo.Type = paramAttrib.Value;
                    }

					//Retrieve and set the OPTIONAL attribute
                    qsParamInfo.Optional = false;
                    paramAttrib = paramNode.Attributes["optional"];
                    if (paramAttrib != null && string.Compare(paramAttrib.Value, "true", true) == 0)
                    {
                        qsParamInfo.Optional = true;
                    }

					//Retrieve and set the CASESENSITIVE attribute
                    qsParamInfo.CaseSensitive = false;
                    paramAttrib = paramNode.Attributes["caseSensitive"];
                    if (paramAttrib != null && string.Compare(paramAttrib.Value, "true", true) == 0)
                    {
                        qsParamInfo.CaseSensitive = true;
                    }

					//Add the parameter to the Parameter collection
                    qsParamColl.Add(qsParamInfo);
                }

				//Add the page and it's parameters to the Config object
                qsPage.Parameters = qsParamColl;
                settings.Pages.Add(qsPage);
            }

			//Select and loop through the customError (should only be one)
            XmlNodeList error = doc.SelectNodes("configuration/customError");
            for (int i = 0; i < error.Count; i++)
            {
                CustomQueryStringError qsError = new CustomQueryStringError();

				//Retrieve and set the MODE attribute
                qsError.Mode = string.Empty;
                XmlAttribute paramAttrib = error[i].Attributes["mode"];
                if (paramAttrib != null)
                {
                    qsError.Mode = paramAttrib.Value;
                }

				//Retrieve and set the EXCEPTIONASSEMBLY attribute
                qsError.ExceptionAssembly = "Tekdev.InputValidation";
                paramAttrib = error[i].Attributes["exceptionAssembly"];
                if (paramAttrib != null)
                {
                    qsError.ExceptionAssembly = paramAttrib.Value;
                }

				//Retrieve and set the EXCEPTIONCLASS attribute
                qsError.ExceptionClass = "InvalidQueryStringException";
                paramAttrib = error[i].Attributes["exceptionClass"];
                if (paramAttrib != null)
                {
                    qsError.ExceptionClass = paramAttrib.Value;
                }

				//Retrieve and set the ERRORMESSAGE attribute
                qsError.ErrorMessage = string.Empty;
                paramAttrib = error[i].Attributes["errorMessage"];
                if (paramAttrib != null)
                {
                    qsError.ErrorMessage = paramAttrib.Value;
                }

				//Add the error to the Config object
                settings.CustomError = qsError;
            }

			//Select and loop through the paramTypes
            XmlNodeList paramTypesNodes = doc.SelectNodes("configuration/paramTypes/add");
            for (int i = 0; i < paramTypesNodes.Count; i++)
            {
                ParameterType paramType = new ParameterType();

				//Retrieve and set the NAME attribute
                XmlNode paramTypeNode = paramTypesNodes[i];
                paramType.Name = string.Empty;
                XmlAttribute paramAttrib = paramTypeNode.Attributes["type"];
                if (paramAttrib != null)
                {
                    paramType.Name = paramAttrib.Value;
                }

				//Retrieve and set the EXPRESSION attribute
                paramType.Expression = string.Empty;
                paramAttrib = paramTypeNode.Attributes["regularExpression"];
                if (paramAttrib != null)
                {
                    paramType.Expression = paramAttrib.Value;
                }

				//Retrieve and set the ERRORMESSAGE attribute
                paramType.ErrorMessage = string.Empty;
                paramAttrib = paramTypeNode.Attributes["errorMessage"];
                if (paramAttrib != null)
                {
                    paramType.ErrorMessage = paramAttrib.Value;
                }

				//Add the paramType to the Config object
                settings.ParameterTypes.Add(paramType);
            }

			//Select and loop through the fileTypes
            XmlNodeList fileTypeNodes = doc.SelectNodes("configuration/fileTypes/add");
            for (int i = 0; i < fileTypeNodes.Count; i++)
            {
                FileType fileType = new FileType();
                XmlNode fileTypeNode = fileTypeNodes[i];

				//Retrieve and set the TYPE attribute
                fileType.Type = string.Empty;
                XmlAttribute paramAttrib = fileTypeNode.Attributes["type"];
                if (paramAttrib != null)
                {
                    fileType.Type = paramAttrib.Value;
                }

				//Retrieve and set the DESCRIPTION attribute
                fileType.Description = string.Empty;
                paramAttrib = fileTypeNode.Attributes["description"];
                if (paramAttrib != null)
                {
                    fileType.Description = paramAttrib.Value;
                }

				//Add the fileType to the Config object
                settings.FileTypes.Add(fileType);
            }

            return settings;
        }

        internal static bool Validate(string configXML, NameValueCollection postedQueryString, QueryStringPage supportedQueryString)
        {
			//Create and load the XmlDocument
            Hashtable types = new Hashtable();
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(configXML);
            XmlElement documentElement = doc.DocumentElement;

			//Loop through the paramTypes to build a list					
			XmlNodeList paramTypes = doc.SelectNodes("configuration/paramTypes/add");
            for (int i = 0; i < paramTypes.Count; i++)
            {
                types[paramTypes[i].Attributes["type"].Value] = paramTypes[i].Attributes["regularExpression"].Value;
            }
			
            if ((postedQueryString != null) && (supportedQueryString != null))
            {
                for (int i = 0; i < supportedQueryString.Parameters.Count; i++)
                {
                    QueryStringParameter paramInfo = supportedQueryString.Parameters[i];
                    string name = paramInfo.Name;
                    string postedValue = postedQueryString[name];
                    if (!paramInfo.Optional)
                    {
                        if (postedValue == null)
                        {   
                            return false;
                        }
                        if (!ValidateParameters(postedValue, types, paramInfo))
                        {
                            return false;
                        }
                    }
                    else if ((paramInfo.Optional && (postedValue != null)) && !ValidateParameters(postedValue, types, paramInfo))
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        private static bool ValidateParameters(string postedValue, Hashtable types, QueryStringParameter paramInfo)
        {
            if (!Regex.IsMatch(postedValue, types[paramInfo.Type].ToString()))
            {
                return false;
            }
            if (paramInfo.Length > -1 && postedValue.Length != paramInfo.Length)
            {
                return false;
            }
            if (paramInfo.MinLength > -1 && postedValue.Length < paramInfo.MinLength)
            {
                return false;
            }
            if (paramInfo.MaxLength > -1 && postedValue.Length > paramInfo.MaxLength)
            {
                return false;
            }
            return true;
        }
		#endregion

    }
}

